using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Markup;
using Rhizome.Contract;
using Rhizome.Contract.Diag;
using Rhizome.Model.Validation;

namespace Rhizome.Model
{
	[ContentProperty("Value")]
	public abstract class Increment<TValue, TStep> : PropertyActionBase
	{
		/// <summary>
		/// 	caches the Plant betwen calls
		/// </summary>
		private object _plant;

		private TStep _step;
		private bool _stepPresent;
		private TValue _value;
		private bool _valuePresent;

		public TStep Step
		{
			[DebuggerStepThrough]
			get { return _step; }
			[DebuggerStepThrough]
			set
			{
				_stepPresent = true;
				_step = value;
			}
		}

		/// <summary>
		/// 	Specify to cache (do not reevaluate) property value between calls
		/// 	Default value: false
		/// </summary>
		public bool CacheValue { get; set; }

		public override sealed void Process()
		{
			if (_plant == null) _plant = Plant;
			if (CacheValue == false || _valuePresent == false)
			{
				_value = (TValue) (Binding.Value);
				_valuePresent = true;
			}
			_value = CountValue(_value);
			Binding.Value = _value;
		}

		protected abstract TValue CountValue(TValue old);

		#region Overrides of PropertyActionBase

		public override IEnumerable<IValidationResult> GetValidationResults()
		{
			return
				_stepPresent
					? base.GetValidationResults()
					: base.GetValidationResults().Concat(new[] {ValidationResult.Error("Step not set")});
		}

		#endregion
	}

	/// <summary>
	/// 	Increments integer property
	/// </summary>
	public sealed class Increment : Increment<int, int>
	{
		#region Overrides of Increment<int>

		protected override int CountValue(int old)
		{
			return old + Step;
		}

		#endregion
	}

	/// <summary>
	/// 	Increments decimal property
	/// </summary>
	public sealed class IncDecimal : Increment<decimal, decimal>
	{
		#region Overrides of Increment<decimal,decimal>

		protected override decimal CountValue(decimal old)
		{
			return old + Step;
		}

		#endregion
	}

	/// <summary>
	/// 	Increments double property
	/// </summary>
	public sealed class IncDouble : Increment<double, double>
	{
		#region Overrides of Increment<double>

		protected override double CountValue(double old)
		{
			return old + Step;
		}

		#endregion
	}

	/// <summary>
	/// 	Increments DateTime property by specific TimeSpan
	/// </summary>
	public sealed class IncDate : Increment<DateTime, TimeSpan>
	{
		#region Overrides of Increment<DateTime,TimeSpan>

		protected override DateTime CountValue(DateTime old)
		{
			return old + Step;
		}

		#endregion
	}

	/// <summary>
	/// 	Increments TimeSpan property
	/// </summary>
	public sealed class IncTimeSpan : Increment<TimeSpan, TimeSpan>
	{
		#region Overrides of Increment<TimeSpan,TimeSpan>

		protected override TimeSpan CountValue(TimeSpan old)
		{
			return old + Step;
		}

		#endregion
	}
}